package com.jinyang.jetpackdemo.util;

import android.os.Handler;
import android.os.HandlerThread;
import android.os.Looper;
import android.os.Message;

import androidx.annotation.NonNull;

import com.google.common.util.concurrent.ThreadFactoryBuilder;

import java.util.Random;
import java.util.concurrent.ArrayBlockingQueue;
import java.util.concurrent.BlockingQueue;
import java.util.concurrent.CopyOnWriteArrayList;
import java.util.concurrent.DelayQueue;
import java.util.concurrent.Delayed;
import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;
import java.util.concurrent.LinkedBlockingQueue;
import java.util.concurrent.PriorityBlockingQueue;
import java.util.concurrent.ScheduledExecutorService;
import java.util.concurrent.ScheduledThreadPoolExecutor;
import java.util.concurrent.SynchronousQueue;
import java.util.concurrent.ThreadFactory;
import java.util.concurrent.ThreadPoolExecutor;
import java.util.concurrent.TimeUnit;

/**
 * @Author: LiuJinYang
 * @CreateDate: 2021/11/11
 * @Description:
 */
public class Test {
    public static void main(String[] args) {
        int a = 1000;
        Integer b = new Integer(a);
        Integer c = Integer.valueOf(a);
        Integer d = new Integer(a);
        System.out.println(a == b);
        System.out.println(b == c);
        System.out.println(b == d);
        System.out.println(b.equals(c));
        System.out.println(b.equals(d));

//        newCachedThreadPool();
//        newFixedThreadPool();
//        newScheduledThreadPool();
//        newSingleThreadExecutor();

//        extracted();

//        new Test().keyword();

//        CopyOnWriteArrayList arrayList = new CopyOnWriteArrayList<>();
//        new Thread(new MyIntegerTask("IntegerTask1")).start();
//        new Thread(new MyStringTask("StringTask1")).start();
//        new Thread(new MyIntegerTask("IntegerTask2")).start();
//        new Thread(new MyStringTask("StringTask2")).start();


    }



    //ThreadLocal用法
    private static final ThreadLocal<Object> threadLocal = new ThreadLocal<Object>() {
        //ThreadLocal没有被当前线程赋值时或当前线程刚调用remove方法后调用get方法，返回此方法值
        @Override
        protected Object initialValue() {
            System.out.println("调用get()时，当前线程共享变量没有设置，调initialValue获取默认值");
            return null;
        }
    };


    public static class MyIntegerTask implements Runnable {
        private String name;

        MyIntegerTask(String name) {
            this.name = name;
        }

        @Override
        public void run() {
            for (int i = 0; i < 5; i++) {
                // ThreadLocal.get方法获取线程变量
                if (null == Test.threadLocal.get()) {
                    // ThreadLocal.et方法设置线程变量
                    Test.threadLocal.set(0);
                    System.out.println("线程" + name + ": 0");
                } else {
                    int num = (Integer) Test.threadLocal.get();
                    Test.threadLocal.set(num + 1);
                    System.out.println("线程" + name + ":" + Test.threadLocal.get());
                    if (i == 3) {
                        Test.threadLocal.remove();
                    }
                }
                try {
                    Thread.sleep(1000);
                } catch (InterruptedException e) {
                    e.printStackTrace();
                }
            }
        }
    }

    public static class MyStringTask implements Runnable {
        private String name;

        MyStringTask(String name) {
            this.name = name;
        }

        @Override
        public void run() {
            for (int i = 0; i < 5; i++) {
                if (null == Test.threadLocal.get()) {
                    Test.threadLocal.set("a");
                    System.out.println("线程" + name + ":a");
                } else {
                    String str = (String) Test.threadLocal.get();
                    Test.threadLocal.set(str + "a");
                    System.out.println("线程" + name + ":" + Test.threadLocal.get());
                }
                try {
                    Thread.sleep(800);
                } catch (InterruptedException e) {
                    e.printStackTrace();
                }
            }
        }
    }

    private volatile int start = 0;

    private void keyword() {

        Runnable runnable = new Runnable() {
            @Override
            public void run() {
                addNum();
            }
        };

        for (int i = 0; i < 10; i++) {
            Thread thread = new Thread(runnable);
            thread.start();
        }

    }

    private void addNum() {
//    private synchronized void addNum() {
        for (int i = 0; i < 100000; i++) {
            start++;
        }
        System.out.println("start = " + start);
    }


    private static void extracted() {
        //线程池不允许使用Executors去创建，而是通过ThreadPoolExecutor的方式，这样的处理方式让写的同学更加明确线程池
        //的运行规则，规避资源耗尽的风险。 说明：Executors返回的线程池对象的弊端如下：
        // 1）FixedThreadPool和SingleThreadPool: 允许的请求队列长度为Integer.MAX_VALUE，可能会堆积大量的请求，
        //从而导致OOM。
        ///2）CachedThreadPool: 允许的创建线程数量为Integer.MAX_VALUE，可能会创建大量的线程，从而导致OOM。

        //Positive example 1：
        //org.apache.commons.lang3.concurrent.BasicThreadFactory
//        ScheduledExecutorService executorService = new ScheduledThreadPoolExecutor(1,
//                new BasicThreadFactory.Builder().namingPattern("example-schedule-pool-%d")
//                .daemon(true).build());

        //Positive example 2：
        ThreadFactory namedThreadFactory = new ThreadFactoryBuilder()
                .setNameFormat("demo-pool-%d").build();

        //Common Thread Pool
        ExecutorService pool = new ThreadPoolExecutor(5, 200,
                0L, TimeUnit.MILLISECONDS,
                new LinkedBlockingQueue<Runnable>(1024), namedThreadFactory, new ThreadPoolExecutor.AbortPolicy());

        pool.execute(() -> System.out.println(Thread.currentThread().getName()));
        pool.shutdown();//gracefully shutdown
    }

    private static void newSingleThreadExecutor() {
        ExecutorService singleThreadExecutor = Executors.newSingleThreadExecutor();
        for (int i = 0; i < 10; i++) {
            final int index = i;
            singleThreadExecutor.execute(new Runnable() {

                @Override
                public void run() {
                    try {
                        System.out.println(Thread.currentThread().getName() + "__" + index);
                        Thread.sleep(2000);
                    } catch (InterruptedException e) {
                        e.printStackTrace();
                    }
                }
            });
        }
    }

    private static void newScheduledThreadPool() {
        //定时
        ScheduledExecutorService scheduledThreadPool = Executors.newScheduledThreadPool(5);
        for (int i = 0; i < 10; i++) {
            final int index = i;
            scheduledThreadPool.schedule(new Runnable() {

                @Override
                public void run() {
                    try {
                        Thread.sleep(2000);
                    } catch (InterruptedException e) {
                        e.printStackTrace();
                    }
                    System.out.println(Thread.currentThread().getName() + "__" + index);
                    System.out.println("delay 3 seconds");
                }
            }, 1, TimeUnit.SECONDS);
        }
        //定期
        scheduledThreadPool.scheduleAtFixedRate(new Runnable() {

            @Override
            public void run() {
                try {
                    Thread.sleep(3000);
                } catch (InterruptedException e) {
                    e.printStackTrace();
                }
                System.out.println(Thread.currentThread().getName() + "__" + "delay 1 seconds, and excute every 3 seconds");
            }
        }, 1, 2, TimeUnit.SECONDS);
    }

    private static void newFixedThreadPool() {
        ExecutorService fixedThreadPool = Executors.newFixedThreadPool(3);
        for (int i = 0; i < 10; i++) {
            final int index = i;
            fixedThreadPool.execute(new Runnable() {

                @Override
                public void run() {
                    try {
                        System.out.println(Thread.currentThread().getName() + "__" + index);
                        Thread.sleep(2000);
                    } catch (InterruptedException e) {
                        e.printStackTrace();
                    }
                }
            });
        }
    }

    private static void newCachedThreadPool() {
        ExecutorService cachedThreadPool = Executors.newCachedThreadPool();
        for (int i = 0; i < 10; i++) {
            final int index = i;
            try {
                Thread.sleep(index % 4 * 1000);
            } catch (InterruptedException e) {
                e.printStackTrace();
            }

            cachedThreadPool.execute(new Runnable() {
                @Override
                public void run() {
                    System.out.println(Thread.currentThread().getName() + "__" + index);
                }
            });
        }
    }

    /**
     * 公平性 构造函数 true
     */
    public static void testArrayBlockingQueue() {
        BlockingQueue<String> abq = new ArrayBlockingQueue<String>(5);
        ExecutorService es = Executors.newCachedThreadPool();
        es.execute(new MyPro(abq, 1000));
        es.execute(new MyCus(abq, 5000));
        es.shutdown();
    }

    /**
     * 基于链表节点的可设置容量的队列，先进先出，队尾插入元素，队首获取元素。
     * 链表队列比基于数据的队列有更高的存取效率，但是在并发应用中效率无法预测。
     */
    public static void testLinkedBlockingQueue() {
        BlockingQueue<String> abq = new LinkedBlockingQueue<String>(5);
        ExecutorService es = Executors.newCachedThreadPool();
        es.execute(new MyPro(abq, 20));
        es.execute(new MyCus(abq, 2000));
        es.shutdown();
    }

    /**
     * DelayQueue
     * 无容量限制的阻塞队列，元素包含延迟时限，只有到达时限，元素才能被取出。
     * 队列顶部是距离到期时间最远的元素。
     * 如果所有的元素都未到期，将会返回null。
     * 元素在执行getDelay()方法返回值小于等于0时过期，即使没有被通过take或者poll执行提取，它们也会被当作一般元素对待。
     * 队列size方法返回所有元素的数量。
     * 队列不能包含null元素。
     */
    public static void testDelayQueue() throws InterruptedException {
        DelayQueue<MyDelayItem> dq = new DelayQueue<MyDelayItem>();
        ExecutorService es = Executors.newFixedThreadPool(5);
        es.execute(new MyDelayPro(dq, 1000));
        es.execute(new MyDelayCus(dq, 10000));
        es.shutdown();
    }

    /**
     * 无容量限制的阻塞队列，元素顺序维持策略同PriorityQueue一样，支持阻塞获取
     * 不允许添加null元素
     * 元素必须支持排序
     * 支持集合遍历，排序
     */
    public static void testPriorityBlockingQueue() throws InterruptedException {
        PriorityBlockingQueue<MyPriorityItem> pbq = new PriorityBlockingQueue<MyPriorityItem>();
        ExecutorService es = Executors.newFixedThreadPool(5);
        es.execute(new MyPriorityBlockingQueuePro(pbq, 1000));
        es.execute(new MyPriorityBlockingQueueCus(pbq, 10000));
        es.shutdown();
    }

    /**
     * 阻塞队列，插入元素和提取元素必须同步。
     * 异步队列没有容量的概念。
     * 无法使用peek，因为只有当你尝试移除时，元素才会存在。
     * 无法插入元素，除非有另外一个线程同时尝试获取元素。
     * 不支持遍历操作，因为队列中根本没有元素。
     * 队列的顶部就是尝试插入元素的线程要插入的元素。
     * 如果没有尝试插入元素的线程，那么就不存在能够提取的元素，poll会返回null。
     * 集合操作contains返null
     * 不允许插入null元素
     */
    public static void testSynchronousQueue() throws InterruptedException {
        SynchronousQueue<String> sq = new SynchronousQueue<String>();
        ExecutorService es = Executors.newFixedThreadPool(5);
        es.execute(new MySynchronousQueuePro(sq, 1000));
        es.execute(new MySynchronousQueueCus(sq, 2000));
        es.shutdown();
    }
}

/**
 * 测试生产者
 */
class MyPro implements Runnable {

    private BlockingQueue<String> bq;

    private int period = 1000;

    private Random r = new Random();

    MyPro(BlockingQueue bq, int period) {
        this.bq = bq;
        this.period = period;
    }

    public void run() {
        try {
            while (true) {
                Thread.sleep(period);
                String value = String.valueOf(r.nextInt(100));
                if (bq.offer(value)) { //offer 能够插入就返回true，否则返回false
                    System.out.println("pro make value: " + value + " queue : " + bq.toString());
                    System.out.println("******************************************************");
                }
            }
        } catch (InterruptedException e) {
            e.printStackTrace();
        }
    }
}

/**
 * 测试消费者
 */
class MyCus implements Runnable {

    private BlockingQueue<String> bq;

    private int period = 1000;

    private Random r = new Random();

    MyCus(BlockingQueue bq, int period) {
        this.bq = bq;
        this.period = period;
    }

    public void run() {
        try {
            while (true) {
                Thread.sleep(period);
                String value = bq.take(); //获取队列头部元素，无元素则阻塞
                System.out.println("cus take value: " + value + " queue : " + bq.toString());
                System.out.println("======================================================");
            }
        } catch (InterruptedException e) {
            e.printStackTrace();
        }
    }
}

/**
 * 延迟队列元素 实现排序
 */
class MyDelayItem implements Delayed {

    private long liveTime;

    private long removeTime;

    MyDelayItem(long liveTime, long removeTime) {
        this.liveTime = liveTime;
        this.removeTime = TimeUnit.MILLISECONDS.convert(liveTime, TimeUnit.MILLISECONDS) + System.nanoTime();
    }

    public long getDelay(TimeUnit unit) {
        return unit.convert(removeTime - System.nanoTime(), unit);
    }

    public int compareTo(Delayed o) {
        if (o == null) return -1;
        if (o == this) return 0;
        if (o instanceof MyDelayItem) {
            MyDelayItem tmp = (MyDelayItem) o;
            if (liveTime > tmp.liveTime) {
                return 1;
            } else if (liveTime == tmp.liveTime) {
                return 0;
            } else {
                return -1;
            }
        }
        long diff = getDelay(TimeUnit.MILLISECONDS) - o.getDelay(TimeUnit.MILLISECONDS);
        return diff > 0 ? 1 : diff == 0 ? 0 : -1;
    }

    public String toString() {
        return "{livetime: " + String.valueOf(liveTime) + ", removetime: " + String.valueOf(removeTime) + "}";
    }
}

/**
 * 延迟队列测试生产者
 */
class MyDelayPro implements Runnable {

    private DelayQueue<MyDelayItem> dq;

    private int period = 1000;

    private Random r = new Random();

    MyDelayPro(DelayQueue dq, int period) {
        this.dq = dq;
        this.period = period;
    }

    public void run() {
        try {
            while (true) {
                Thread.sleep(period);
                if (dq.size() > 5) {
                    continue;
                }
                MyDelayItem di = new MyDelayItem(r.nextInt(10), r.nextInt(10));
                dq.offer(di);
                System.out.println("delayqueue: add---" + di.toString() + "size: " + dq.size());
                System.out.println("*************************************");
            }
        } catch (InterruptedException e) {
            e.printStackTrace();
        }
    }
}

/**
 * 延迟队列测试消费者
 */
class MyDelayCus implements Runnable {

    private DelayQueue<MyDelayItem> dq;

    private int period = 1000;

    MyDelayCus(DelayQueue dq, int period) {
        this.dq = dq;
        this.period = period;
    }

    public void run() {
        try {
            while (true) {
                Thread.sleep(period);
                MyDelayItem di = dq.take();
                System.out.println("delayqueue: remove---" + di.toString());
                System.out.println("delayqueue: ---" + dq.toString());
                System.out.println("======================================");
            }
        } catch (InterruptedException e) {
            e.printStackTrace();
        }
    }
}

/**
 * 延迟队列元素 时限排序对比延迟队列
 */
class MyPriorityItem implements Comparable<MyPriorityItem> {

    private int priority;

    MyPriorityItem(int priority) {
        this.priority = priority;
    }

    /**
     * 数字大优先级高
     *
     * @param o
     * @return
     */
    public int compareTo(MyPriorityItem o) {
        if (o == null) return -1;
        if (o == this) return 0;
        if (priority > o.priority) {
            return -1;
        } else if (priority == o.priority) {
            return 0;
        } else {
            return 1;
        }
    }

    public String toString() {
        return "{priority: " + String.valueOf(priority) + "}";
    }
}

/**
 * 优先队列测试生产者
 */
class MyPriorityBlockingQueuePro implements Runnable {

    private PriorityBlockingQueue<MyPriorityItem> pbq;

    private int period = 1000;

    private Random r = new Random();

    MyPriorityBlockingQueuePro(PriorityBlockingQueue pbq, int period) {
        this.pbq = pbq;
        this.period = period;
    }

    public void run() {
        try {
            while (true) {
                Thread.sleep(period);
                if (pbq.size() > 5) {
                    continue;
                }
                MyPriorityItem pi = new MyPriorityItem(r.nextInt(10));
                pbq.offer(pi);
                System.out.println("PriorityBlockingQueue: add---" + pi.toString() + " size: " + pbq.size());
                System.out.println("PriorityBlockingQueue: " + pbq.toString());
                System.out.println("*************************************");
            }
        } catch (InterruptedException e) {
            e.printStackTrace();
        }
    }
}

/**
 * 优先队列测试消费者
 */
class MyPriorityBlockingQueueCus implements Runnable {

    private PriorityBlockingQueue<MyPriorityItem> pbq;

    private int period = 1000;

    private Random r = new Random();

    MyPriorityBlockingQueueCus(PriorityBlockingQueue pbq, int period) {
        this.pbq = pbq;
        this.period = period;
    }

    public void run() {
        try {
            while (true) {
                Thread.sleep(period);
                MyPriorityItem di = pbq.take();
                System.out.println("PriorityBlockingQueue: remove---" + di.toString());
                System.out.println("PriorityBlockingQueue: ---" + pbq.toString());
                System.out.println("======================================");
            }
        } catch (InterruptedException e) {
            e.printStackTrace();
        }
    }
}

/**
 * 阻塞队列测试生产者
 */
class MySynchronousQueuePro implements Runnable {

    private SynchronousQueue<String> sq;

    private int period = 1000;

    private Random r = new Random();

    MySynchronousQueuePro(SynchronousQueue sq, int period) {
        this.sq = sq;
        this.period = period;
    }

    public void run() {
        try {
            while (true) {
                Thread.sleep(period);
                String value = String.valueOf(r.nextInt(100));
                if (sq.offer(value)) {
                    System.out.println("pro make value: " + value + " synchronous :" + sq.toString());
                    System.out.println("******************************************************");
                }
            }
        } catch (InterruptedException e) {
            e.printStackTrace();
        }
    }
}

/**
 * 阻塞队列测试消费者
 */
class MySynchronousQueueCus implements Runnable {

    private BlockingQueue<String> sq;

    private int period = 1000;

    MySynchronousQueueCus(BlockingQueue sq, int period) {
        this.sq = sq;
        this.period = period;
    }

    public void run() {
        try {
            while (true) {
                Thread.sleep(period);
                String value = sq.take();
                System.out.println("cus take value: " + value + " synchronous :" + sq.toString());
                System.out.println("======================================================");
            }
        } catch (InterruptedException e) {
            e.printStackTrace();
        }
    }
}
